/* various functions generating puzzles

*/
extern GAME Tblgame;
extern	FOUTPUT output1,output2;

 void GO_PAT::UNPAS::Init(GO_PAT * parent) {
	 myparent=parent;
	 libres.SetAll_1();
	 nlibres=81;
	 parent->nsol=0;
	 parent->cp1=0;
	 for(int i=0;i<81;i++){//1;i<81;i++){
		  td[i].f=0x1ff;
		  mypuz.puz[i]='.';
	 }
 }

 void GO_PAT::UNPAS::Fixer(int i,USHORT  ch ) {
	 if(libres.Off(i)) 
		 return;  
	 libres.Clear(i); 
	 nlibres--;
//     tu[i].Fixer(ch);
	 td[i].f=0;
//	 Clear(i,ch);
	 mypuz.puz[i]=ch+'1';
 }

void GO_PAT::UNPAS::SetLimitDigits(BF81 & cells,USHORT digits){
	USHORT tp[100],ntp=cells.String(tp);
	for(int i=0;i<ntp;i++)
		td[tp[i]].f &=digits;
}

void GO_PAT::UNPAS::Exo_Game(USHORT * tc,int ntc,int minfixed){
	myparent->cp1=0;
	myparent->ntest++;
	GAME & mygame =game[20]; //keep start  untouched for filters
	mygame.InitSudoku(mypuz.puz,20);
	int ir=mygame.DoUpdate();
	if(ir -2) return; // already wrong or solved !!
	if(0 && myparent->ntest<10){
		output2<<mypuz.puz <<" ntc="<<ntc<<endl;
		game[20].Debug(1);
	}

	mygame.GenPat1(tc,ntc,minfixed);
}




//==================================================================



void GO_PAT::Start(){
	cout << "genpat start"<< endl;
	if((cop23-52) &&(cop23-61)&&(cop23-65)){ // file2 used with option 52;61
			(*myout2)<<"options summary mode gen pat"<<endl;
			(*myout2)<<"process "<< cop23<<endl;
			(*myout2)<<"nassigned "<< nassigned<<endl;
			(*myout2)<<"filter    "<< filter<<endl;
			(*myout2)<<"ch_ski    "<< change_skip<<endl;
			(*myout2)<<"fix_then  "<< fix_then<<endl;
			(*myout2)<<"use max assigned "<< usemaxassigned<<endl;
			(*myout2)<<"id linit 2         "<< usemaxassigned2<<endl;
			(*myout2)<<"use filter       "<< usefilter<<endl;
			(*myout2)<<"id limit 2         "<< usefilter2<<endl;
			(*myout2)<<"canonical output "<< canonical_in_output<<endl;
			(*myout2)<<"up to mode       "<< gen_up_to_mode<<endl;
			(*myout2)<<"G= in output     "<< subgroup_in_output<<endl;
			(*myout2)<<"not minimal chk  "<< no_minimal<<endl;
			if(options.first)
				(*myout2)<<"options.first  "<< options.first<<endl;

	}
	if(subgroup_in_output){
		(*myout1)<<"G= "<<endl;
		(*myout2)<<"G= "<<endl;
	}
	cptl=0;

	switch (cop23){
		// 1x is work on pattern
    case 11:  Do_11();     return;// change n clues or up to n clues
	case 12:  Do_12();     return;// apply "11" except for "fix" clues at the start
	case 14:  Do_14();     return; // first record cell tagged 'A' locked apply "11" on other clues
	case 15:  // twin generation 
		break;
	case 20: Do_20();	  return; //guided scan rec 1 is pattern 
	case 21: Do_21();	  return; // rec 1 is pattern gen seeds
	case 22: Do_22();	  return; // full scan all valid

	case 31: case 32: case 33: case 34: case 35: // gen symmetry of given
		     Do_3x(); return;

	case 41:  Do_41();     return;// - x + y
	case 42:  Do_42();     return;// change x add 1
	case 43:  Do_43();     return;// change x kill 1

	case 51: Do_51();	  return; //extract minimal and sub minimal

	case 60: case 61: case 63: 
		Do_60();     return;// gen on pattern close to exocet
	case 64: case 65: 
		Do_64();     return;// gen on pattern  main diag swordfish
	case 99: Do_99();     return; // gen on a specific pattern

	}



}
	
void GO_PAT::SetFinal_Same_Pat(char * source){
	puzfinal=puzin;
	for(int i=0;i<81;i++){
		if(puzfinal.puz[i]-'.')
			puzfinal.puz[i]=source [i];
	}
}

void GO_PAT::SetFinal_Partiel(char * source){
	puzfinal=puzin;
	for(int i=0;i<nclues;i++){
		int ii=tclues[i];
		puzfinal.puz[ii]=source [ii];
	}

}	

void GO_PAT::Do_11(){  // change n clues or up to nclues
	if(change_skip>4){
		(*myout2)<<"processing cancelled change to high"<<endl ;
		return;
	}
	puzfix.Empty();
	while(myin->GetPuzzle(puzin.puz)){
		(*myout2)<<puzin.puz<<" go"<<endl;
		puzin.TableClues(tclues,nclues);
		puzvar.Create(puzin.puz);
		Do_1x();
	}
}


void GO_PAT::Do_12(){  // same 11  after fix first n or >5 fix=0
	if(change_skip>8 || fix_then>9){
		(*myout2)<<"processing cancelled change or fix to high"<<endl ;
		return;
	}
	while(myin->GetPuzzle(puzin.puz)){
		(*myout2)<<puzin.puz<< " go "<<endl;
		puzvar.Create(puzin.puz);
		puzfix.Empty();
		puzout=puzin; // to prepare tclues later
		int nfix=0;
		for(int i=0;i<81;i++){
			if(nfix==fix_then) break;
			if(puzvar.puz[i]){
				puzfix.puz[i]=puzvar.puz[i];
				puzvar.puz[i]=0;
				puzout.puz[i]='.';
				nfix++;
			}
		}
        puzout.TableClues(tclues,nclues);		
	    Do_1x();
	}
}


void GO_PAT::Do_14(){  // change n clues or up to nclues "-1" contains fix clues tagged 'A'
	if((!options.first) ||	(strlen(options.first)-81) ){
		(*myout2)<< " pattern missing or length not correct "<<endl;
		return;
	}
	(*myout2)<<options.first<< " A is fixed "<<endl;
	char zs[82];
	zs[81]=0;
	PUZ0 puzd;
	puzd.Empty();
    for(int i=0;i<81;i++)
			if(options.first[i]=='A') puzd.puz[i]=1;
	     // now the lot of puzzles to process

	while(myin->GetPuzzle(puzin.puz)){
		(*myout2)<<"processing"<<endl<<puzin.puz<<endl;
		puzfix.Empty();
        puzout=puzin;   // relay to extarct clues
		for(int i=0;i<81;i++)
			if(puzd.puz[i]){
				puzout.puz[i]='.';
				if(puzin.puz[i]=='.'){ // not the right pattern
					(*myout2)<<"process stopped due to invalid pattern"<<endl;
					cout<<"\n\nprocess stopped due to invalid pattern\n\n"<<endl;
					return;
				}
				puzfix.puz[i]=puzin.puz[i]-'0';
				puzout.puz[i]='.';
			}
		puzout.TableClues(tclues,nclues);
		puzvar.Create(puzout.puz);
		Do_1x();
	}
}

void GO_PAT::Do_1x(){  // change n clues or up to nclues
 /* process valid for one puzzles in options 11 to 14
   . one PUZ0 with values to fix       puzf
   . one table of values to change     tclues

*/
  dep.Init(this);    

   for(int i=0;i<81;i++) {
	   int j=puzfix.puz[i];
	   if(j)
		   dep.Fixer(i,j-1);     // puzfix zerobased             
   }
   UNPAS depr=dep;
   COMBINE combi; 
   int idep=change_skip;
   if(gen_up_to_mode)
	   idep=1;
             //========== up to n loop
   for(UINT ichange=idep;ichange<=change_skip;ichange++){
 	 int nfix=nclues-ichange;
	 combi.First(nclues,ichange,tclues,tclues_s);
     while(1 ) {
	   dep=depr;
		for(int i=0;i<nfix;i++){
			int ii=tclues_s[i]; 
			int j=puzvar.puz[ii];
			dep.Fixer(ii,j-1);                
		} 
		// to use the common process, force remaining clues to change
		USHORT * tcl=& tclues_s[nfix];
		for(int i=0;i<(int)ichange;i++){
			int cell=tcl[i];
			dep.td[cell].Clear(puzvar.puz[cell]-1); 
		}
		dep.Exo_Game(tcl,ichange ,0); 
//		dep.Pattern_Plus_Pat(& tclues_s[nfix],ichange );
        if(!combi.Next()) break; 
     } 
   }

}

void GO_PAT::Do_20(){  
/* guided scan
   rec1 is the pattern where
    'A' is known
	'B' is 'to generate
	digit is 'not to be generated. keep it as it is in output

*/

	(*myout2)<< " entry in guided scan "<<endl;
	char zs[82];
	zs[81]=0;
	PUZ0 puzd;
	puzd.Empty();
	if((!options.first) ||	(strlen(options.first)-81) ){
		(*myout2)<< " pattern missing or length not correct "<<endl;
		return;
	}
	(*myout2)<<options.first<< " pattern "<<endl;
	USHORT tc[81],ntc=0;
	nclues=0;
	nta=0;
	for(int i=0;i<81;i++) {
		int c=options.first[i];
		if(c=='A') ta[nta++]=i;
		else if(c=='B') tclues[nclues++]=i;
		else if(c-'.') tc[ntc++]=i;
	}
	if(!nclues){
			(*myout2)<< " stopped due to nothing to generate "<<endl;
			return;
	}

	(*myout2)<<"given ="<<nta<< " nclues = "<<nclues<< " ntc=" <<ntc<<endl;

	if(ntc && canonical_in_output){
		for(int i=0;i<81;i++) {
			int c=options.first[i];
			if(c=='A' || c=='B') puzpat.puz[i]='1';
			else  puzpat.puz[i]='.';
			if(c-'.')puzfinal.puz[i]='1';
			else  puzfinal.puz[i]='.';
		}
		go_can.Study_Perms_Sym(puzfinal.puz);
		(*myout2)<<" nbperms final"<<go_can.wsym.nfinal<<endl;
		  // check if perms valid for that one

		(*myout2)<< " first "<<puzpat.puz <<endl;

		for(int i=0;i<go_can.wsym.nfinal;i++){
			PUZC puzw=puzpat;
			 GO_CAN::WSYM_PERM wp=go_can.wsym.tp[i];
			for(int j=0;j<9;j++){
				VV9 ws0,ws; // ws source reordered
				//create source vector
				int wrc=wp.perm1[j];
				if(wrc<9)
					ws0.row(puzpat.puz,wrc);
				else
					ws0.col(puzpat.puz,wrc-9);
				for(int k=0;k<9;k++) 
					ws.v[k]=ws0.v[wp.perm2[k]];
				for(int k=0;k<9;k++){
					int id;
					if(wp.target_is_row)
						id=9*j+k;
					else
						id=j+9*k;
					puzw.puz[id]=ws.v[k];
				}
			}
			(*myout2)<< " perm  source ";
			for(int i=0;i<9;i++)
				(*myout2)<< wp.perm1[i]<<" ";
			(*myout2)<< " target is row" <<wp.target_is_row<< " perm2 " ;
			for(int i=0;i<9;i++)
				(*myout2)<< wp.perm2[i]<<" ";
			(*myout2)<<endl;
			
			if(strncmp(puzpat.puz,puzw.puz,81)){
				canonical_in_output=0;
				(*myout2)<< puzpat.puz<< " puzpat" <<endl;
				(*myout2)<< puzw.puz << "puzw"  <<endl;

				(*myout2)<< "killed can in output "<<endl;
				break;
			}

		}

	}


	while(myin->GetPuzzle(puzin.puz)){
		(*myout2)<<puzin.puz<< " go "<<endl;
		dep.Init(this);    
		puzfix.Create(puzin.puz);
		puzvar.Empty();  // all values authorized
		int minfix=9;
		for(int i=0;i<nta;i++) {
			int ii=ta[i], j=puzfix.puz[ii];
			 if(j)
				dep.Fixer(ii,j-1);     // puzfix zerobased  
			 if((j-1)<minfix) minfix=j-1;
			}

		if(!ntc) // no more unknown, this is the last step
			dep.Exo_Game(tclues,nclues ,minfix);
		else {// partial process 
			cp1=0;
			GAME & mygame =game[20];
			mygame.InitSudoku(dep.mypuz.puz,20);
			int ir=mygame.DoUpdate();
			if(mygame.DoUpdate() -2) return; // already wrong or solved !!
			mygame.Pattern_Partial(tc,ntc,minfix);
		}		
	}	
}

void GO_PAT::Do_21(){  
/* seed generator for the pattern gam
   command -1 gives the pattern
   here no filter so
   v1 is the band stack (0-5) to use as start
   v2 is the number of clues to use as first phase 
   per main combination
   v3 is the number of seeds to collect (max)
   v4 is the max number of puzzles to study  

*/

	(*myout2)<< " entry in seed generation "<<endl;
	if((!options.first) ||	(strlen(options.first)-81) ){
		(*myout2)<< " pattern missing or length not correct "<<endl;
		return;
	}
	(*myout2)<<options.first<< " pattern "<<endl;
	// check validity of parameters or set default valur
	if(options.v1>5) options.v1=0;
	if(options.v2<5 || options.v2>12)options.v2=10;
	if(options.v3<1 || options.v3>10) options.v3=1;
	if(options.v4<100 || options.v4>100000) options.v4=1000;

	// derived from do-11
	nclues=0;
	puzfix.Empty();
	for(int i=0;i<81;i++) {
		int c=options.first[i];
		if(c>='1' && c<='9') {
			tclues[nclues++]=i;
			puzin.puz[i]=c;
		}
		else puzin.puz[i]='.';
	}
	puzin.puz[81]=0;
	(*myout2)<<puzin.puz<<" go"<<endl;
	if(nclues<20){
		(*myout2)<< " stopped due to nclues too small nclues = "<< nclues<<endl;
		return;
	}
//	puzvar.Create(puzin.puz);

	// put required band/stack at the top
	int ncluesa=0;
	for(int i=0;i<nclues;i++) {
		int cl=tclues[i],cla;
		if(options.v1<3) cla=cl/27; // band
		else cla = 3+ (cl%9)/3; // stack
		if(cla==options.v1){ // must be in the top
			if(ncluesa==i)ncluesa++;
			else{
				tclues[i]=tclues[ncluesa];
				tclues[ncluesa++]=cl;
			}
		}
	}
	ncluesa=options.v2; // force to count using the top of the table
//	if(ncluesa >= (int)options.v2) ncluesa=options.v2;
	(*myout2)<< " start seed generation ncluesa= "<< ncluesa
		<< " nclues= "<< nclues<< endl
		<< " number of puzzles per start "<< options.v3 <<endl
		<< " max number of count per start "<< options.v4 <<endl;
	// set first clue to 9 and Go
	GAME & mygame =game[20];
	mygame=Tblgame;
	mygame.index=20;
	mygame.Seta(8,tclues[0]);
	mygame.GenSeed0(&tclues[1],ncluesa-1,nclues-1,8);
}


void GO_PAT::Do_22(){  // full scan
	while(myin->GetPuzzle(puzin.puz)){
		(*myout2)<<puzin.puz<< " start full "<< endl;
		puzin.TableClues(tclues,nclues);
		GAME & mygame =game[20];
		mygame=Tblgame;
		mygame.index=20;
		mygame.Seta(8,tclues[0]);
		mygame.GenFull(&tclues[1],nclues-1,8);

	}
}

void GO_PAT::Do_51(){  // extract minimal output 1 rank -1 output 2

	while(myin->GetPuzzle(puzin.puz)){
		int aigmin=1;
		for(int i=0;i<81;i++){
			if(puzin.puz[i]-'.'){
				char pp[82]; strcpy (pp,puzin.puz); pp[i]='.';
				if(1 == game[0].CheckValidityQuick(pp)) {
					(*myout2)<<pp<<endl;
					aigmin=0;
				}
			}
		}
		if(aigmin)
			(*myout1)<<puzin.puz<<endl;
	}
}

void GO_PAT::Sym_36(int type){ 
/* tables used in symmetry processing
   [36][2] sd1_36  diagonal  sd2_36 diag 2   sst_36 stick
   sym_81[5][81] direct sym   d1  d2 st cc r90
   sym_f9[3][9] fix positions  d1 d2 stick

   sym_tcor[1][9]  pairing 34 56 78  1;2;3 self

*/
	(*myout2)<<" entry sym_36 type= "<<type<<endl;
	nclues=0;  // on finira par diagonale

	USHORT (* p_36_2)[2]=(!type)?sd1_36:(type<2)?sd2_36:sst_36;

	for(int i=0;i<36;i++) {
		USHORT * vv=p_36_2[i];
		int ij=vv[0],ji=vv[1];
	    if(puzin.puz[ij]-'.') {// un clue
			if (puzin.puz[ji]=='.') return; // not the expected pattern
			tclues[nclues++]=ij;   tclues[nclues++]=ji; 
	   }
		else if (puzin.puz[ji]-'.') return; //not the expected pattern
	} 

	USHORT tcf[9],ntcf=0;  // look now for clues on fix cells
	USHORT *vf=sym_f9[type];
	for(int i=0;i<9;i++)   {
		int ii=vf[i];if(puzin.puz[ii]-'.') tcf[ntcf++]=ii;
	}
	(*myout2)<<" ntcf= "<<ntcf<<" nclues= "<<nclues<<endl;
	GAME::glb.ptcor=sym_tcor[1];
	game[0]=Tblgame;
	game[0].Sym_36_F(tcf,ntcf,tclues,nclues,0);
	     
}

void GO_PAT::Sym_C(){ 
/* tables used in symmetry processing
   sc_40[40][2] central   sr90_20[20][4] rot 90
   sym_81[5][81] direct sym   d1  d2 st cc r90
   sym_tcor[0]([9])  pairing 12 34 56 78  0 self

*/
	nclues=0;   
	for(int i=0;i<40;i++) {
		USHORT * vv=sc_40[i];
		int ij=vv[0],ji=vv[1];
	    if(puzin.puz[ij]-'.') {// un clue
			if (puzin.puz[ji]=='.') return; // not the expected pattern
			tclues[nclues++]=ji;   tclues[nclues++]=ij; // table shows first highest
	   }
		else if (puzin.puz[ji]-'.') return; //not the expected pattern
	} 

	// now a loop on possible number of self image clues  1 3 5 7 9
	game[0]=Tblgame;
	GAME::glb.ptcor=sym_tcor[0];
	game[0].Seta(0,40);
	game[0].Sym_xx(tclues,nclues,1);
	     
}

void GO_PAT::Sym_R90(){ 
/* tables used in symmetry processing
    sr90_20[20][4] rot 90
   sym_81[5][81] direct sym   d1  d2 st cc r90
   sym_tcor[5][9]  pairing from 1 to 9   1;3;5;7;9

*/
	nclues=0;   
	for(int i=0;i<20;i++) {
		USHORT * vv=sr90_20[i];
	    if(puzin.puz[vv[0]]-'.') {// un clue
			for(int j=1;j<3;j++)
			  if (puzin.puz[vv[j]]=='.') 
				  return; // not the expected pattern
			for(int j=0;j<4;j++)
				tclues[nclues++]=vv[j];    
	   }
		else for(int j=1;j<3;j++)
			  if (puzin.puz[vv[j]] - '.') 
				  return; // not the expected pattern
	} 
	(*myout2)<<"r90 start nclues= "<<nclues<<endl;

	// now a loop on possible number of self image clues  1 3 5 7 9
	game[0]=Tblgame;
	GAME::glb.ptcor=sym_tcor[2];
	game[0].Seta(0,40);
//	game[0].Sym_R90(tclues,nclues,1);
	     
}

void GO_PAT::Do_3x(){
	/* entry point for all search of symmetry
	   process voluntarily limited to one pattern
	*/
	if(!myin->GetPuzzle(puzin.puz)) return;
	(*myout2)<<puzin.puz<< " go "<<endl;

	switch(optg->cop3){
	case 1:	case 2:	case 3:	//main diagonal  second diagonal  stick  
		Sym_36(optg->cop3-1); return;
	case 4:	Sym_C();return;	// central
	case 5:	Sym_R90();return;	// r90

	}
}

void GO_PAT::Do_41(){  // -'v3' + 'v4"
/* processing a -x+y without pattern constraint
   fix given except x
   take y in the free cells and try all
   in 0 based puzvar unassigned cells are set to 10 for later process
*/

	if(change_skip>3 || fix_then>3){
		(*myout2)<<"processing cancelled change or fix to high"<<endl ;
		return;
	}
	if(change_skip<1 || fix_then<1){
		(*myout2)<<"processing cancelled change or fix missing"<<endl ;
		return;
	}

 	puzvar.Empty(); // in that process all new assigned are free

	while(myin->GetPuzzle(puzin.puz)){
		(*myout2)<<puzin.puz<< " go "<<endl;

		puzfix.Create(puzin.puz); // 0 based puzzle for fix

		USHORT tclues_empty[81],tclues_empty_s[81],nclues_empty=0;
		nclues=0;
		// fill the 2 clues tables
		for(int i=0;i<81;i++) 
			if(puzin.puz[i]-'.'){
			tclues[nclues++]=i;
			}
			else{
				tclues_empty[nclues_empty++]=i;
			}
		PUZC puzinr=puzin;
		COMBINE combi_free,combi_given; 
		combi_given.First(nclues,change_skip,tclues,tclues_s);
		int ngiven=nclues-change_skip,nfree=nclues_empty-fix_then;
			
			// =====================loop on all perm for combi_given
		 while(1 ) {
			dep.Init(this);
			for(int i=0;i<ngiven;i++){//take all given from the perm
				int ii=tclues_s[i]; 
				int j=puzfix.puz[ii];
				dep.Fixer(ii,j-1);     
			} 
			puzin=puzinr;		// prepare puzout with emptied cells
			for(int i=ngiven;i<nclues;i++){//emptied from the perm
				int ii=tclues_s[i]; 
				puzin.puz[ii]='.' ;               
			} 

			PUZC puzin3=puzin; // save that position
			UNPAS depr=dep;
			/*
			output1 << "depr situation"<<endl
			   << depr.mypuz.puz<<endl<<hex;
			for(int i=0;i<9;i++){
				for(int j=0;j<9;j++)
					output1 << depr.td[9*i+j].f<<" ";
				output1 << endl;
			}

			*/
	
			   // now start the loop on free cells to assign
			combi_free.First(nclues_empty,fix_then,
				             tclues_empty,tclues_empty_s);

			   // ===================loop2 on free cells perms
			
			 while(1 ) {
				 // nothing to do out of non selected cells
				 puzin=puzin3;
				 dep=depr;
				for(int i=nfree;i<nclues_empty;i++){//to assign from the perm
					int ii=tclues_empty_s[i]; 
					puzin.puz[ii]='1' ;   // dummy to say it is in the solution
				} 
				dep.Exo_Game(& tclues_empty_s[nfree],fix_then ,0);
				if(!combi_free.Next()) break; 
			 }
			if(!combi_given.Next()) break; 
		}  
	}	
}

void GO_PAT::Do_42(){  //change 'v3' + add 1

	if(change_skip>3 || change_skip<1){
		(*myout2)<<"processing cancelled change not 1/3"<<endl ;
		return;
	}
	puzvar.Empty(); // in that process all new assigned are free
	while(myin->GetPuzzle(puzin.puz)){
		(*myout2)<<puzin.puz<< " go "<<endl;
		puzfix.Create(puzin.puz); // 0 based puzzle for fix
		USHORT tclues_empty[81],nclues_empty=0;
		nclues=0;
		// fill the 2 clues tables
		for(int i=0;i<81;i++) 
			if(puzin.puz[i]-'.')
				tclues[nclues++]=i;			 
			else
				tclues_empty[nclues_empty++]=i;			
		PUZC puzinr=puzin;
		COMBINE combi_given; 
		combi_given.First(nclues,change_skip,tclues,tclues_s);
		int ngiven=nclues-change_skip;
			
			// =====================loop on all perm for combi_given
		 while(1 ) {
//			 (*myout1)<< "change "<<cellsFixedData[tclues_s[ngiven] ].pt
//			 << " "<<cellsFixedData[tclues_s[ngiven+1] ].pt<<endl;
			dep.Init(this);
			for(int i=0;i<ngiven;i++){//take all given from the perm
				int ii=tclues_s[i]; 
				int j=puzfix.puz[ii];
				dep.Fixer(ii,j-1);     
			} 
			// to use the common process, force selected  clues to change
			for(int i=ngiven;i<nclues;i++){
				int cell=tclues_s[i] ;
				dep.td[cell].Clear(puzin.puz[cell]-'1'); 
			}

			UNPAS depr=dep;	
			   // now start the loop on free cells to assign added to tcles_s
			for(int i2=0;i2<nclues_empty;i2++) {
				 dep=depr;
				 int ii=tclues_empty[i2]; 
				 puzin=puzinr;
				 puzin.puz[ii]='1' ;   // dummy to say it is in the solution
				 tclues_s[nclues]=ii; 
	//			 (*myout1)<<puzin.puz<< "add " <<endl;
				 dep.Exo_Game(& tclues_s[ngiven],change_skip+1 ,0);
			 }
			if(!combi_given.Next()) break; 
		}  
	}	
}

void GO_PAT::Do_43(){  //change 'v3' + kill 1

	if(change_skip>5|| change_skip<2){
		(*myout2)<<"processing cancelled change not 2/5"<<endl ;
		return;
	}
	puzvar.Empty(); // in that process all new assigned are free
	while(myin->GetPuzzle(puzin.puz)){
		(*myout2)<<puzin.puz<< " go "<<endl;
		puzfix.Create(puzin.puz); // 0 based puzzle for fix
		USHORT tclues_empty[81],nclues_empty=0;
		nclues=0;
		// fill the 2 clues tables
		for(int i=0;i<81;i++) 
			if(puzin.puz[i]-'.')
				tclues[nclues++]=i;			 
			else
				tclues_empty[nclues_empty++]=i;			
		PUZC puzinr=puzin;
		COMBINE combi_given; 
		combi_given.First(nclues,change_skip+1,tclues,tclues_s);
		int ngiven=nclues-change_skip-1;
			
			// =====================loop on all perm for combi_given
		 while(1 ) {
			dep.Init(this);
			for(int i=0;i<ngiven;i++){//take all given from the perm
				int ii=tclues_s[i]; 
				int j=puzfix.puz[ii];
				dep.Fixer(ii,j-1);     
			} 
			UNPAS depr=dep;	
			   // now start the loop on free cells to assign added to tcles_s
			COMBINE combi_changed; 
			combi_changed.First(change_skip+1,change_skip,&tclues_s[ngiven],tclues_s2);
			while(1){
				puzin=puzinr;
				int ii=tclues_s2[0]; 
				puzin.puz[ii]='.' ;   // it is not in the solution
				dep=depr;
				dep.Exo_Game(& tclues_s2[1],change_skip ,0);
				if(!combi_changed.Next()) break; 
			}

			if(!combi_given.Next()) break; 
		}  
	}	
}



int GO_PAT::Do_59Mini(char * ze ){
/*  subroutine checking an existing puzzle is minimum
    kill one clues and see whether the puzzle has only one solution
	the puzzle is supposed to be valid
*/
	for(int i=0;i<81;i++)	if(ze[i]-'.'){
		char pp[82]; strcpy (pp,ze); pp[i]='.';
		if(1==game[0].CheckValidityQuick(pp)) 
			return 0;  // not valid if any subgrid is valid
	}
return 1;}

void GO_PAT::Do_60(){ // gen on pattern close to exocet 4 digits
	while(myin->GetPuzzle(puzin.puz)){
		sel61=gencount=0;
		if(cop23-61) (*myout2)<<myin->ze<< " go new puzzle";
		PUZC puzinr=puzin;
		int aigok=1;
		for(int i=0;i<81;i++){
			char c=puzin.puz[i];
			if(c-'.' && c-'1') {aigok=0; break;}
		}
		if(!aigok) {
			if(cop23-61)(*myout2)<< " not a pattern puzzle "<<endl;
			continue;
		}
		if(cop23-61)(*myout2)<<endl;
		// first morph the puzzle to an exocet start
		// compute the count per box
		USHORT nb[9];

		PUZ0 mypuz0;
		mypuz0.Create(puzin.puz);
		BF81 w81;
		for(int i=0;i<81;i++)
			if(mypuz0.puz[i]) w81.Set(i);
		for(int i=18;i<27;i++){
			BF81 ww(cellsInHouseBM[i]);
			nb[i-18]=(ww & w81).Count();
		}
		
		for(int i=0;i<9;i++) if(nb[i]>=3 && nb[i]<6 ){// a possible start for exocet
			if(w81.Count()>22 && nb[i]<4) continue; // should be too long
			PUZC_SYM puzw;
			// morph the puzzle with expected box in box 1
			puzw.ExchangeBoxes(puzinr.puz,18,i+18); // ne colle pas 
//			if(cop23-61)(*myout2)<< puzw.puz<< " before symmetry  box "<<i+1<<endl;
			if(cop23<62)Do_60A(puzw);
			else Do_63A(puzw);
			if(puzw.IsNotPatMainDiagSymmetry()){
				puzw.DoMainDiagSymmetry();
				puzw.DoGiven();
//				if(cop23-61)(*myout2)<< puzw.puz<< " after symmetry " <<endl;
				if(cop23<62) Do_60A(puzw);
				else Do_63A(puzw);
			}
		}
		if((!sel61) && cop23==61)
			(*myout2)<<myin->ze<<endl;
	}
}

void GO_PAT::Do_60A(PUZC_SYM & pu){ // box one and rotate done
	BF81 wbox(cellsInHouseBM[18],pu.given);
	for(int irow=0;irow<3;irow++){// test all 3 mini lines for 2 holes seeing 5 or more given
		BF81 minir(cellsInHouseBM[irow],wbox);
		if(minir.Count()>1) continue; // one or no  given in the mini row

		USHORT trows[9],tcols[9];
		for(int i2=0;i2<9;i2++) trows[i2]=tcols[i2]=i2;
		trows[0]=irow; trows[irow]=0;
		// we work with a given in box2 row2 and in box 3 row3
		BF81 stack2(cellsInBandBM[4],pu.given),stack3(cellsInBandBM[5],pu.given),
			r2_81(cellsInHouseBM[trows[1]],pu.given),r3_81(cellsInHouseBM[trows[2]],pu.given),
			stack23= stack2 | stack3, r23_81= r2_81 | r3_81;
		if((r23_81 & stack2).IsEmpty() || (r23_81 & stack3).IsEmpty()) continue;


		target_one_row=0;
		if((r2_81 & stack23).IsEmpty() || (r3_81 & stack23).IsEmpty()){
			// can be targets in the same row
			if((r2_81 & stack23).IsEmpty() ){ // put given in row 2
				USHORT temp=trows[1];
				trows[1]=trows[2];
				trows[2]=temp;
			}

			target_one_row=1;
		}
		else if((r2_81 & stack2).IsEmpty() || (r3_81 & stack3).IsEmpty()){ // exchange rows 2 and 3
			USHORT temp=trows[1];
			trows[1]=trows[2];
			trows[2]=temp;
		}

		if(minir.Count()==1){	// morph to have in cells r1c12
			PUZC_SYM  pu2;
			for(int j=0;j<3;j++)
				if(minir.On(9*irow+j)){// this is the given put it as last
					if(j<2){tcols[j]=2; tcols[2]=j;}
					break;
				}
		pu2.Morph(pu.puz,trows,tcols);
		Do_60B(pu2 );
		continue;
		}
		// now this is a mini row with no given try three possibilities for the base
		BF81 r1_81(cellsInHouseBM[trows[0]],pu.given);
		if((r1_81 |wbox).Count() <5) continue; // base must see 5 given
		// question ?? should it be at least one per box

		for(int j=0;j<3;j++){
			PUZC_SYM  pu2;
			tcols[0]=j; tcols[1]=(j+1)%3; tcols[2]=(j+2)%3; 
			pu2.Morph(pu.puz,trows,tcols);
			Do_60B(pu2);
		}

		
	}
}

void GO_PAT::Do_60B(PUZC_SYM & pu2 ){ // box one and rotate done
	pu2.DoGiven();
//	if(cop23-61)(*myout2)<< pu2.puz<< " base cells 12 r2 stack2 not empty one_row="<<target_one_row <<endl;
	BF81 wbox2(cellsInHouseBM[18],pu2.given),
		 wr1(cellsInHouseBM[0],pu2.given),
		 wseen=wbox2 |wr1;
	USHORT nseen=wseen.Count();
	if(nseen<5) return;
	// preferably columns 12 should be nearly empty
	// and receive only the base digits
	// but this is not ok for 3 digits
	BF81 col1_81(cellsInHouseBM[9],pu2.given),
		 col2_81(cellsInHouseBM[10],pu2.given),
		 col3_81(cellsInHouseBM[11],pu2.given);
	col1_81-=wbox2;
	col2_81-=wbox2;
	col3_81-=wbox2;

	if(col3_81.Count()<2) return;// may be one per box filter -c[18]
	if(options.command_c[18]=='1'){
		BF81 b4(cellsInHouseBM[21],pu2.given),
		b7(cellsInHouseBM[24],pu2.given);
		if((b4 & col3_81).IsEmpty()) return;
		if((b7 & col3_81).IsEmpty()) return;
	}



	if(col1_81.Count()>2 || col2_81.Count()>2) return;// reasonable limit
	if(col1_81.Count()+ col2_81.Count()>3) return; // same
	// try all possibilities for c4 and c7 having the target
	PUZC_SYM  pu3;
	int targ2d=(target_one_row)?15:24;
	for(int i1=0;i1<3;i1++){
	  if(pu2.puz[12+i1]=='.') continue; // only pure JE 
	  for(int i2=0;i2<3;i2++){
		if(pu2.puz[targ2d+i2]=='.') continue; // only pure JE 
		USHORT trows2[9],tcols2[9];
		for(int ix=0;ix<9;ix++) trows2[ix]=tcols2[ix]=ix;
		tcols2[3]=3+i1; tcols2[3+i1]=3;
		tcols2[6]=6+i2; tcols2[6+i2]=6;
		pu3.Morph(pu2.puz,trows2,tcols2);
		pu3.DoGiven();
		strcpy(puzin.puz,pu3.puz); 
		puzfix.Create(pu3.puz);   
		// find all given that can no be base to  have a pure exocet pattern
		BF81 unseen,
			wr1_3(cellsInHouseBM[0],pu3.given),
			wseen_3=wbox2 |wr1_3;
		int ttw[7]={1,2,9,10,11,12,15}; // rows 2,3 cols 3 4 7
		// cols 12 added but have a specific treatment later
		for(int k=0;k<7;k++)
			unseen |= cellsInHouseBM[ttw[k]];
		unseen &= pu3.given;
		unseen -= wseen_3;
		int nbase=4;  // here only exocet 4 digits
		if((nbase+nseen)<9) continue;
		int nfree=9-nbase;
		BF16 fbase(0,1,2,3),ffree;
		ffree.f=0x1ff ^ fbase.f;  // the other digits
		BF81 myunseen=unseen,myclues=pu3.given-wbox2,
			mystack1(cellsInBandBM[3],unseen); 
		UNPAS depstart;
		// try a generation for nbase
		depstart.Init(this);  
		int minfix=nbase;    // to avoid duplication for base digits
		USHORT tb1[10],ntb1=wbox2.String(tb1); // assign box1
		int nextassign=nbase;
		BF16 assigned_box1;
		for(int i=0;i<ntb1;i++) {
			assigned_box1.Set(nextassign);
			depstart.Fixer(tb1[i],nextassign++);  
		}
		myunseen |= (wr1_3-wbox2);
		int nass=assigned_box1.bitCount();
		USHORT tr1[10],ntr1=(wr1_3-wbox2).String(tr1); // see row 1
		if(nass==5){
			Do_60C(pu3,depstart,myclues,myunseen,mystack1,assigned_box1 ,minfix ,col1_81,col2_81);
			continue;
		}
		//  be sure to have all digits assigned
		int lim = ntr1-4+nass; // one or 2 levels of loop
		for(int i1=0;i1<lim;i1++){
			UNPAS dep2=depstart;
			BF81 myunseen2=myunseen,myclues2=myclues;
			dep2.Fixer(tr1[i1],nextassign);  
			myclues2.Clear(tr1[i1]);
			myunseen2.Clear(tr1[i1]);
			if(nass==4){
				Do_60C(pu3,dep2,myclues2,myunseen2,mystack1,assigned_box1 ,minfix ,col1_81,col2_81);
				continue;
			}
			for(int i2=i1+1;i2<ntr1;i2++){
				UNPAS dep2b=dep2;
				BF81 myunseen2b=myunseen2,myclues2b=myclues2;
				dep2b.Fixer(tr1[i2],nextassign+1);  
				myclues2b.Clear(tr1[i2]);
				myunseen2b.Clear(tr1[i2]);
				Do_60C(pu3,dep2b,myclues2b,myunseen2b,mystack1,assigned_box1 ,minfix ,col1_81,col2_81);
			}
		}
	  }
	}
}

void GO_PAT::Do_60C(PUZC_SYM & pu,UNPAS & dep2,BF81 & myclues,BF81 & myunseen,BF81 & mystack1,
	BF16 assigned_box1,int minfix ,BF81 & col1_81,BF81 & col2_81 ){
			// call without any fix in stack1
			Do_60Go(pu,dep2,myclues,myunseen,mystack1,assigned_box1 ,minfix ); 
				// now look stack1	 can be base digits keeping open the base
			// limit is 2 given per column, usually less (total 3)
			BF81 * cola=&col1_81, *colb=&col2_81;
			if(col1_81.Count()>  col2_81.Count()){// one given first
				cola=&col2_81; colb=&col1_81; 
			}
			USHORT tcola[20],ncola=cola->String(tcola),
				   *tcolb=&tcola[ncola],ncolb=colb->String(tcolb);
			int nstack1=ncola+ncolb;
			if(!nstack1) return; // nothing to do
			//make one call with each cell set to digit 4
			for(int i=0;i<nstack1;i++){
				int cell=tcola[i];
				UNPAS dep3=dep2;
				BF81 myunseen3=myunseen,myclues3=myclues,mystack1_3=mystack1;
				dep3.Fixer(cell,3);  // set digit 4
				myclues3.Clear(cell);
				myunseen3.Clear(cell);
				mystack1_3.Clear(cell);
				Do_60Go(pu,dep3,myclues3,myunseen3,mystack1_3,assigned_box1 ,minfix-1 ); 
			}
				if(nstack1<2) return;
			int cell=tcola[0];
			UNPAS dep3=dep2;
			BF81 myunseen3=myunseen,myclues3=myclues,mystack1_3=mystack1;
			dep3.Fixer(cell,3);  // set digit 4
			myclues3.Clear(cell);
			myunseen3.Clear(cell);
			mystack1_3.Clear(cell);
			// Now add a cell from tcolb
			for(int icol=1;icol<nstack1;icol++){
				int cell=tcola[icol];
				UNPAS dep4=dep3;
				BF81 myunseen4=myunseen3,myclues4=myclues3,mystack1_4=mystack1_3;
				dep4.Fixer(cell,2);  // set digit 3
				myclues4.Clear(cell);
				myunseen4.Clear(cell);
				mystack1_4.Clear(cell);
				Do_60Go(pu,dep4,myclues4,myunseen4,mystack1_4,assigned_box1 ,minfix-2 ); 
				}
			// could also put one base digit  in column 4!!!!
			// but this is more a seed generator already very long process

}


void GO_PAT::Do_60Go(PUZC_SYM & pu,UNPAS & depo,BF81 & myclues,BF81 & myunseen,BF81 & mystack,
	BF16 assigned_box1 ,int minfix ){
	if((cop23 == 61 || cop23 == 65) && sel61) return; 
	// optionnal filter required significant match of given in rows having given in colum 3
	if(options.command_c[15]=='1'){
		BF81 b1(cellsInBandBM[0],pu.given),
			c3g(cellsInHouseBM[11],pu.given),
			c4g(cellsInHouseBM[12],pu.given),
			c7g(cellsInHouseBM[15],pu.given),
			matchg;
		c3g-=b1;
		USHORT t3g[10],nt3g=c3g.String(t3g); //should have at least 2 given
		matchg.SetAll_0();
		for(int i=0;i<nt3g;i++){
			int cell=t3g[i],row=cellsFixedData[cell].el;
			BF81 ww (cellsInHouseBM[row],pu.given);
			matchg|=ww;
		}
		matchg &= (c4g | c7g);
		if(matchg.Count()<2) return; 
		if(options.command_c[16]=='1' && matchg.Count()<3) return;
		if(options.command_c[17]=='1' && matchg.Count()<4) return;
	}



	int nbase=4;  // here only exocet 4 digits
	int nfree=9-nbase;
	BF16 fbase(0,1,2,3),ffree;
		ffree.f=0x1ff ^ fbase.f;  // the other digits

	// force cells in my unseen to free digits only
	depo.SetLimitDigits(myunseen,ffree.f);
	// and limitstack 1 to digits assigned in box 1
	depo.SetLimitDigits(mystack,assigned_box1.f);
	BF81 wwa=myunseen & myclues; // non base  digits only first
	nclues=wwa.String(tclues); //all other digits for generation
	int nclues1=nclues;
	nclues+=(myclues-wwa).String(&tclues[nclues]); //all other digits for generation
//	if(nclues-nclues1>7) return; // seems very long in that position
	if(cop23 == 61 || cop23 == 65){
		sel61=1;
		(*myout1) <<myin->ze<< endl;
		return;
	}
	if(options.command_c[20]=='1'){// from change_skip to fix_then included
		gencount++;
		if(gencount<change_skip) return;
		if(gencount>fix_then) return;
	}

	(*myout2)<<pu.puz<< " being processed "<<endl;

	dep=depo; // dep is supposed to have the start in "zhou" process
	if(1){
		(*myout2)<< " clues det ";
		char ws[10];
		for(int i=0;i<nclues1;i++){
			int cell=tclues[i];
			BF16 wd=depo.td[cell];
			(*myout2)<< " " << cellsFixedData[cell].pt<< " " << wd.String(ws);
		}
		(*myout2) <<endl << " residual number of clues " << nclues<<endl;
		(*myout2) <<depo.mypuz.puz<< " starting position" << endl;
	}
	if(!options.diag)  // keep diag as filter to check the pre generation
		//if(options.test)
		dep.Exo_Game(tclues,nclues,minfix );
		//else depo.Pattern_Plus_Pat_Exo(tclues,nclues,minfix );

}

void GO_PAT::Do_63A(PUZC_SYM & pu){ // box one and rotate done
	BF81 wbox(cellsInHouseBM[18],pu.given);
	for(int irow=0;irow<3;irow++){// test all 3 mini lines for 2 holes seeing 5 or more given
		BF81 minir(cellsInHouseBM[irow],wbox);
		int mincount=minir.Count();
		if(mincount>1) continue; //maximum  one given in the mini row
		// morph to have in cells r1c12
		PUZC_SYM  pu2;
		USHORT trows[9],tcols[9];
		for(int i2=0;i2<9;i2++) trows[i2]=tcols[i2]=i2;
		trows[0]=irow; trows[irow]=0;
		if(mincount==1){
			for(int j=0;j<3;j++)
				if(minir.On(9*irow+j)){// this is the given put it as last
					if(j<2){tcols[j]=2; tcols[2]=j;}
					break;
				}
		}
		else { // must try 3 possibilities for the digits that must be forced


		}
		// we work with a given in box2 row2 and in box 3 row3
		BF81 stack2(cellsInBandBM[4],pu.given),stack3(cellsInBandBM[5],pu.given),
			r2_81(cellsInHouseBM[trows[1]],pu.given),r3_81(cellsInHouseBM[trows[2]],pu.given),
			stack23= stack2 | stack3, r23_81= r2_81 | r3_81;
		if((r2_81 & stack23).IsEmpty() || (r3_81 & stack23).IsEmpty()) continue;
		if((r23_81 & stack2).IsEmpty() || (r23_81 & stack3).IsEmpty()) continue;


		if((r2_81 & stack2).IsEmpty()){ // exchange rows 2 and 3
			USHORT temp=trows[1];
			trows[1]=trows[2];
			trows[2]=temp;
		}

		pu2.Morph(pu.puz,trows,tcols);
		pu2.DoGiven();
		BF81 wbox2(cellsInHouseBM[18],pu2.given),
			 wr1(cellsInHouseBM[0],pu2.given),
			 wseen=wbox2 |wr1;
		USHORT nseen=wseen.Count();
		if(nseen<5) continue;
		if(nseen==5) Do_63A5( pu2);
		else  Do_63A6( pu2);
	}
}

void GO_PAT::Do_63A5(PUZC_SYM & pu2){ // 5 seen must add one in box
	BF81 wbox2(cellsInHouseBM[18],pu2.given),
		 wr1(cellsInHouseBM[0],pu2.given),
		 wseen=wbox2 |wr1;
	USHORT nseen=wseen.Count();
	// start from a minirow empty
	BF81 col1_81(cellsInHouseBM[9],pu2.given),
		 col2_81(cellsInHouseBM[10],pu2.given);
	col1_81-=wbox2;
	col2_81-=wbox2;
	// this seems good but is not granted
	if(col1_81.Count()>1 || col2_81.Count()>1) return;
	// try all possibilities for c4 and c7 having the target
	PUZC_SYM  pu3;
	for(int i1=0;i1<3;i1++){
	  if(pu2.puz[12+i1]=='.') continue; // only pure JE 
	  for(int i2=0;i2<3;i2++){
		if(pu2.puz[24+i2]=='.') continue; // only pure JE 
		USHORT trows2[9],tcols2[9];
		for(int ix=0;ix<9;ix++) trows2[ix]=tcols2[ix]=ix;
		tcols2[3]=3+i1; tcols2[3+i1]=3;
		tcols2[6]=6+i2; tcols2[6+i2]=6;
		pu3.Morph(pu2.puz,trows2,tcols2);
		pu3.DoGiven();
		// find all given that can no be base to  have a pure exocet pattern
		BF81 unseen,
			wr1_3(cellsInHouseBM[0],pu3.given),
			wseen_3=wbox2 |wr1_3;
		int ttw[5]={1,2,11,12,15}; // rows 2,3 cols 3 4 7
		for(int k=0;k<5;k++)
			unseen |= cellsInHouseBM[ttw[k]];
		unseen &= pu3.given;
		unseen -= wseen_3;


		for(int nbase=4;nbase<5;nbase++){ // not base 3 in test
			if((nbase+nseen)<9) continue;
			int nfree=9-nbase;
			BF16 fbase(0,1,2),ffree;
			BF81 myunseen=unseen,myclues=pu3.given-wbox2,
				mycolumn3(cellsInHouseBM[11],pu2.given);;
			if(nbase==4) fbase.Set(3);
			ffree.f=0x1ff ^ fbase.f;  // the other digits
				// try a generation for nbase
			dep.Init(this);  
			// voir le sens de ces 3 lignes
			puzfix.Create(pu3.puz);   
			int minfix=nbase;    // try to avoid duplication for free digits

			USHORT tb1[10],ntb1=wbox2.String(tb1); // assign box1
			int nextassign=nbase;
			BF16 assigned_box1;
			for(int i=0;i<ntb1;i++) {
				assigned_box1.Set(nextassign);
				dep.Fixer(tb1[i],nextassign++);  
			}

			USHORT tr1[10],ntr1=(wr1_3-wbox2).String(tr1); // see row 1

			if(nseen==nfree){
				for(int i=0;i<ntr1;i++) {
					dep.Fixer(tr1[i],nextassign++);  
					myclues.Clear(tr1[i]);
				}
			}
			else {//must contain free digits
				myunseen |= (wr1_3-wbox2);
			}
			// force cells in my unseen to free digits only
			dep.SetLimitDigits(myunseen,ffree.f);
			// and limit column 3 to digits assigned in box 1
			dep.SetLimitDigits(mycolumn3,assigned_box1.f);

			// in option, if base 4 digits and one given in cols 12
			// try a base digit
			BF81 cols12=col1_81 | col2_81;
			if( nbase == 4 && cols12.Count() == 1){
				int cell=cols12.First();
				dep.Fixer(cell,3);
				myclues.Clear(cell);
				minfix--; 				
			}
			BF81 wwa=myunseen & myclues; // free digits only first
			nclues=wwa.String(tclues); //all other digits for generation
			nclues+=(myclues-wwa).String(&tclues[nclues]); //all other digits for generation

			if(1){
				unsigned long number_perms=1;
				(*myout2)<<pu3.puz<< " being processed "<<endl;
				(*myout2) << " clues det ";
				char ws[10];
				for(int i=0;i<nclues;i++){
					int cell=tclues[i];
					BF16 wd=dep.td[cell];
					(*myout2)<< " " << cellsFixedData[cell].pt<< " " << wd.String(ws);
					number_perms*=wd.bitCount();
				}
				(*myout2) <<endl;
				(*myout2) <<dep.mypuz.puz<< " starting position" << endl;
			}
			strcpy(puzin.puz,pu3.puz); 
			dep.Exo_Game(tclues,nclues,minfix );
			nclues+=(myclues-wwa).String(&tclues[nclues]); //all other digits for generation
			dep.Exo_Game(tclues,nclues,minfix );
		}
	}}
}

void GO_PAT::Do_63A6(PUZC_SYM & pu2){ // box one and rotate done
	BF81 wbox2(cellsInHouseBM[18],pu2.given),
		 wr1(cellsInHouseBM[0],pu2.given),
		 wseen=wbox2 |wr1;
	USHORT nseen=wseen.Count();
	BF81 col1_81(cellsInHouseBM[9],pu2.given),
		 col2_81(cellsInHouseBM[10],pu2.given);
	col1_81-=wbox2;
	col2_81-=wbox2;
	if(col1_81.Count()>2 || col2_81.Count()>2) return;// reasonable limit
	if(col1_81.Count()+ col2_81.Count()>3) return; // same
	// try all possibilities for c4 and c7 having the target
	PUZC_SYM  pu3;
	for(int i1=0;i1<3;i1++){
	  if(pu2.puz[12+i1]=='.') continue; // only pure JE 
	  for(int i2=0;i2<3;i2++){
		if(pu2.puz[24+i2]=='.') continue; // only pure JE 
		USHORT trows2[9],tcols2[9];
		for(int ix=0;ix<9;ix++) trows2[ix]=tcols2[ix]=ix;
		tcols2[3]=3+i1; tcols2[3+i1]=3;
		tcols2[6]=6+i2; tcols2[6+i2]=6;
		pu3.Morph(pu2.puz,trows2,tcols2);
		pu3.DoGiven();
		strcpy(puzin.puz,pu3.puz); 
		puzfix.Create(pu3.puz);   
		// find all given that can no be base to  have a pure exocet pattern
		BF81 unseen,
			wr1_3(cellsInHouseBM[0],pu3.given),
			wseen_3=wbox2 |wr1_3;
		int ttw[7]={1,2,9,10,11,12,15}; // rows 2,3 cols 3 4 7
		// cols 12 added but have a specific treatment later
		for(int k=0;k<7;k++)
			unseen |= cellsInHouseBM[ttw[k]];
		unseen &= pu3.given;
		unseen -= wseen_3;
		int nbase=3;  // here only exocet 4 digits
		if((nbase+nseen)<9) continue;
		int nfree=9-nbase;
		BF16 fbase(0,1,2,3),ffree;
		ffree.f=0x1ff ^ fbase.f;  // the other digits
		BF81 myunseen=unseen,myclues=pu3.given-wbox2,
			mystack1(cellsInBandBM[3],unseen); 
		 
		// try a generation for nbase
		dep.Init(this);  
		int minfix=nbase;    // to avoid duplication for base digits
		USHORT tb1[10],ntb1=wbox2.String(tb1); // assign box1
		int nextassign=nbase;
		BF16 assigned_box1;
		for(int i=0;i<ntb1;i++) {
			assigned_box1.Set(nextassign);
			dep.Fixer(tb1[i],nextassign++);  
		}
		USHORT tr1[10],ntr1=(wr1_3-wbox2).String(tr1); // see row 1
		myunseen |= (wr1_3-wbox2);
		int ir1=0;
		while(ir1++<ntr1+1){ // no assignment or 1 assignment in row 1
			UNPAS dep2=dep;
			BF81 myunseen2=myunseen,myclues2=myclues;
			if(ir1 == 1){
				if( assigned_box1.bitCount()==4) continue; // need one more
				else{ // nothing to do
				}
			}
			else if( assigned_box1.bitCount()==5) break; // finished if box 1 5 given
			else {
				dep2.Fixer(tr1[ir1-2],nextassign);  
				myclues2.Clear(tr1[ir1-2]);
				myunseen2.Clear(tr1[ir1-2]);
			}				
			// call without any fix in stack1
			Do_60Go(pu3,dep2,myclues2,myunseen2,mystack1,assigned_box1 ,minfix ); 
			// now look stack1	 can be base digits keeping open the base
			// limit is 2 given per column, usually less (total 3)
			BF81 * cola=&col1_81, *colb=&col2_81;
			if(col1_81.Count()>  col2_81.Count()){// one given first
				cola=&col2_81; colb=&col1_81; 
			}
			USHORT tcola[5],ncola=cola->String(tcola),tcolb[5],ncolb=colb->String(tcolb);
			int nstack1=ncola+ncolb;
			if(!nstack1) continue; // nothing to do
			//make one call with each cell set to digit 4
			for(int i=0;i<nstack1;i++){
				int cell=tcola[0];
				if(i) cell =tcolb[i-1];
				UNPAS dep3=dep2;
				BF81 myunseen3=myunseen2,myclues3=myclues2,mystack1_3=mystack1;
				dep3.Fixer(cell,3);  // set digit 4
				myclues3.Clear(cell);
				myunseen3.Clear(cell);
				mystack1_3.Clear(cell);
				Do_60Go(pu3,dep3,myclues3,myunseen3,mystack1_3,assigned_box1 ,minfix-1 ); 
			}
			if(nstack1<2) continue;
			int cell=tcola[0];
			UNPAS dep3=dep2;
			BF81 myunseen3=myunseen2,myclues3=myclues2,mystack1_3=mystack1;
			dep3.Fixer(cell,3);  // set digit 4
			myclues3.Clear(cell);
			myunseen3.Clear(cell);
			mystack1_3.Clear(cell);
			// Now add a cell from tcolb
			for(int icolb=0;icolb<ncolb;icolb++){
				int cell=tcolb[0];
				UNPAS dep4=dep4;
				BF81 myunseen4=myunseen3,myclues4=myclues3,mystack1_4=mystack1_3;
				dep4.Fixer(cell,2);  // set digit 3
				myclues4.Clear(cell);
				myunseen4.Clear(cell);
				mystack1_4.Clear(cell);
				Do_60Go(pu3,dep4,myclues4,myunseen4,mystack1_4,assigned_box1 ,minfix-2 ); 
			}
			// could also put one base digit  in column 4!!!!
			// but this is more a seed generator already very long process
		}
	}}
}



void GO_PAT::Do_64(){ // gen exo on pattern close to exocet 4 digits
	while(myin->GetPuzzle(puzin.puz)){
		sel61=gencount=0;
		if(cop23-65) (*myout2)<<myin->ze<< " go new puzzle mode 64/65";
		int aigok=1;
		for(int i=0;i<81;i++){
			char c=puzin.puz[i];
			if(c-'.' && c-'1') {aigok=0; break;}
		}
		if(!aigok) {
			if(cop23-65)(*myout2)<< " not a pattern puzzle "<<endl;
			continue;
		}
		if(cop23-65)(*myout2)<<endl;  // 65 is same as 61 split on selected puzzles
		// want box1 diagonal free and ocupied top left
		char * cw=puzin.puz;
		if(cw[2]-'.' || cw[10]-'.' || cw[18] -'.'||
			cw[0]=='.' || cw[1]=='.' || cw[9] =='.') continue;
		(*myout2)<< " box1 is ok "<<endl;
		PUZC_SYM pu;
		pu.Create(puzin.puz);  		pu.DoGiven();
		BF81 b1(cellsInHouseBM[18],pu.given);
		BF81 b2(cellsInHouseBM[19],pu.given);
		BF81 b3(cellsInHouseBM[20],pu.given);
		BF81 b23=b2 | b3;
		BF81 b4(cellsInHouseBM[21],pu.given);
		BF81 b7(cellsInHouseBM[24],pu.given);
		BF81 b47=b4|b7;
		// problem in bitfield if done in once?? 
		BF81 r1=(cellsInHouseBM[0]);
		BF81 r2=(cellsInHouseBM[1]);
		BF81 r3=(cellsInHouseBM[2]);
		BF81 c1=(cellsInHouseBM[9]);
		BF81 c2=(cellsInHouseBM[10]);
		BF81 c3=(cellsInHouseBM[11]);
		r1 &=b23;   r2 &=b23;   r3 &=b23;
		c1 &= b47;  c2 &= b47;  c3 &= b47;
		BF81 r123=r1|(r2|r3),c123=c1|(c2|c3);


		// minimum 3 given in box 1, up to 6
		int nb1=b1.Count();
		if(nb1<5) continue; // will see later for 3 or 4 
		(*myout2)<< " box1 count "<< nb1 <<endl;
		dep.Init(this);  
		USHORT tb1[10],ntb1=b1.String(tb1); // assign box1
		int nextassign=9-nb1;
		BF16 assigned_box1;
		for(int i=0;i<ntb1;i++) {
			assigned_box1.Set(nextassign);
			dep.Fixer(tb1[i],nextassign++);  
		}

		// so far we look for a matrix 3x3 or 3x4 of given in boxes 5;6;8;9
		BF16 rows,cols;
		USHORT tr[20],ntr=r123.String(tr),tc[20],ntc=c123.String(tc);
		if(ntr>4 || ntc>4) continue; // to see later

		(*myout2)<< " ntr= "<< ntr << " ntc= "<< ntc  <<endl;

		for(int i=0;i<ntc;i++)
			rows.Set(cellsFixedData[tc[i]].el); // rows come from cols 123
		for(int i=0;i<ntr;i++)
			cols.Set(cellsFixedData[tr[i]].pl);

		(*myout2)<< " nrows= "<< rows.bitCount() << " ncols= "<< cols.bitCount()  <<endl;


		if(rows.bitCount() <3 || cols.bitCount() < 3 ||
			rows.bitCount() >4 || cols.bitCount()>4) continue;
		// collect all given at cells intersecting rows and cols
		BF81 prows,pcols,pxx;
		prows.SetAll_0(); pcols.SetAll_0();
		for(int i=3;i<9;i++){
			if(rows.On(i)){
				BF81 ww(cellsInHouseBM[i],pu.given);
				prows |= ww;
			}
			if(cols.On(i)){
				BF81 ww(cellsInHouseBM[i+9],pu.given);
				pcols |= ww;
			}
		}
		pxx= prows & pcols; // now given at the crossings
		USHORT tx[20],ntx=pxx.String(tx); 

		(*myout2)<< " crossings "<<  ntx  <<endl;
		if(ntx<5) continue; // this is my example

		// now tr is band1 b23 tc is satck1 b47 tx is crossings b5689
		BF81 bs=r123 | c123; // all given in band stack out of box1
		USHORT tbs[20],ntbs=bs.String(tbs),unass=0x1ff ^ assigned_box1.f,
			minfix=9-assigned_box1.bitCount();

		dep.SetLimitDigits(bs,assigned_box1.f); // limited to box1 unless assigned directly
		dep.SetLimitDigits(pxx,assigned_box1.f);

		BF81 myclues=pu.given-b1,myunseen=bs|pxx;
		if(options.command_c[15]=='1')	{	// very long and not very productive 
			UNPAS dep1=dep;
			Do_64Go(pu,dep1, myclues, myunseen, minfix );
		}
		// often done with a symmetric pattern. reduce the count if symmetric
		BF81 bsx=bs;
		if(pu.IsMainDiagSymmetry()) bsx=r123;
		USHORT tbsx[20],ntbsx=bsx.String(tbsx);
		// now one in bs
		for(int i=0;i<ntbsx;i++){
			UNPAS dep1=dep;
			BF81 myclues1=myclues,myunseen1=myunseen;
			int cell=tbsx[i];
			dep1.Fixer(cell,minfix-1);
			myclues1.Clear(cell);
			myunseen1.Clear(cell);
			Do_64Go(pu,dep1, myclues1, myunseen1, minfix-1 );
		}

		// now one in pxx
		for(int i=0;i<ntx;i++){
			UNPAS dep1=dep;
			BF81 myclues1=myclues,myunseen1=myunseen;
			int cell=tx[i];
			dep1.Fixer(cell,minfix-1);
			myclues1.Clear(cell);
			myunseen1.Clear(cell);
			Do_64Go(pu,dep1, myclues1, myunseen1, minfix-1 );
		}

		int tdiag1[3]={2,10,18};
		// now one  2 in band/stack  same cell in box1 same digit
		for(int i=0;i<3;i++){
			int cellb1=tdiag1[i];
			BF81 rdi=(i==0)?r1:((i==1)?r2:r3),
				cdi=(i==0)?c3:((i==1)?c2:c1);
			USHORT tri[10],ntri=rdi.String(tri),tci[10],ntci=cdi.String(tci);
			for(int i1=0;i1<ntri;i1++) for(int i2=0;i2<ntci;i2++){
				UNPAS dep1=dep;
				BF81 myclues1=myclues,myunseen1=myunseen;
				int cell=tri[i1];
				dep1.Fixer(cell,minfix-1);
				myclues1.Clear(cell);
				myunseen1.Clear(cell);
				cell=tci[i2];
				dep1.Fixer(cell,minfix-1);
				myclues1.Clear(cell);
				myunseen1.Clear(cell);
				(*myout2)<<cellsFixedData[ tri[i1]].pt<<cellsFixedData[ tci[i2]].pt<<endl;
				Do_64Go(pu,dep1, myclues1, myunseen1, minfix-1 );

			}

		}
		// one band1 one pxx same of different digits
		for(int i=0;i<ntbsx;i++){
			int cell1=tbsx[i];
			UNPAS dep1=dep;
			BF81 myclues1=myclues,myunseen1=myunseen;
			dep1.Fixer(cell1,minfix-1);
			myclues1.Clear(cell1);
			myunseen1.Clear(cell1);
			for(int j=0;j<ntx;j++){
				int cell2=tx[j];
				UNPAS dep2=dep1;
				BF81 myclues2=myclues1,myunseen2=myunseen1;
				myclues2.Clear(cell2);
				myunseen2.Clear(cell2);
				//assign the same if unseen by one
				BF81 wws=cellsFixedData[ cell1].z;
				if(wws.Off(cell2)){
					UNPAS dep3=dep2;
					dep3.Fixer(cell2,minfix-1);
					Do_64Go(pu,dep3, myclues2, myunseen2, minfix-1 );
				}
				//assign another
				dep2.Fixer(cell2,minfix-2);
				Do_64Go(pu,dep2, myclues2, myunseen2, minfix-2 );
			}
		}

		if((!sel61) && cop23==65)
			(*myout2)<<myin->ze<<endl;
	}
}



void GO_PAT::Do_64Go(PUZC_SYM & pu,UNPAS & depo,BF81 & myclues,BF81 & myunseen,int minfix ){
	if( cop23 == 65 && sel61) return; 

	nclues= myunseen.String(tclues); //all other digits for generation
	int nclues1=nclues;
	nclues+=(myclues-myunseen).String(&tclues[nclues]); //all other digits for generation
	if( cop23 == 65){
		sel61=1;
		(*myout1) <<myin->ze<< endl;
		return;
	}
	if(options.command_c[20]=='1'){// from change_skip to fix_then included
		gencount++;
		if(gencount<change_skip) return;
		if(gencount>fix_then) return;
	}
	if(1){
		if(!options.diag){
			(*myout2) <<"go for";
			char ws[10];
			for(int i=0;i<nclues1;i++){
				int cell=tclues[i];
				BF16 wd=depo.td[cell];
				(*myout2)<< " " << cellsFixedData[cell].pt<< " " << wd.String(ws);
			}
			(*myout2) <<endl << " residual number of clues " << nclues<<endl;
		}
		(*myout2) <<depo.mypuz.puz<< " starting position" << endl;
	}
	dep=depo;
	if(!options.diag) // keep diag as filter to check the pre generation
		dep.Exo_Game(tclues,nclues,minfix );

}



void GO_PAT::Do_70(){ // gen pattern in +-n mode
	while(myin->GetPuzzle(puzin.puz)){
		(*myout2)<<myin->ze<< " go new puzzle";
		PUZC puzinr=puzin;
		int aigok=1;
		for(int i=0;i<81;i++){
			char c=puzin.puz[i];
			if(c-'.' && c-'1') {aigok=0; break;}
		}
		if(!aigok) {
			(*myout2)<< " not a pattern puzzle "<<endl;
			continue;
		}
		(*myout2)<<endl;
		// first morph the puzzle to an exocet start
		// compute the count per box
		USHORT nb[9];

		PUZ0 mypuz0;
		mypuz0.Create(puzin.puz);
		BF81 w81;
		for(int i=0;i<81;i++)
			if(mypuz0.puz[i]) w81.Set(i);
		for(int i=18;i<27;i++){
			BF81 ww(cellsInHouseBM[i]);
			nb[i-18]=(ww & w81).Count();
		}
		
		for(int i=0;i<9;i++) if(nb[i]>=3 && nb[i]<6 ){// a possible start for exocet
			PUZC_SYM puzw;
			// morph the puzzle with expected box in box 1
			puzw.ExchangeBoxes(puzinr.puz,18,i+18); // ne colle pas 
			(*myout2)<< puzw.puz<< " before symmetry  box "<<i+1<<endl;
			if(puzw.IsNotPatMainDiagSymmetry()){
				puzw.DoMainDiagSymmetry();
				puzw.DoGiven();
				(*myout2)<< puzw.puz<< " after symmetry " <<endl;
			}
		}
	}
}



void GO_PAT::Do_99(){ // g17 g18 row1 1.. 1.. 1.. from 1.. 1.. vicinity 
	// entry is a 18 clues puzzles 2 clues per row/col 1 clue per mini row mini col
	// output same exchange one clue change 1 to 3 clues
	ntest=0;
	int tminirow[27],tbloc_col[3][9],tcluesr[20],ncluesr;
	while(myin->GetPuzzle(puzin.puz)){
		(*myout2)<<myin->ze<< " go new puzzle"<<endl;
		for(int i=0;i<27;i++)
			tminirow[i]=tbloc_col[i/9][i%9]=0;
		ncluesr=0;		// fill the tables
		for(int i=0;i<81;i++) {
			if(puzin.puz[i]-'.'){
				tcluesr[ncluesr++]=i;
				tminirow[i/3]++;
				tbloc_col[i/27][i%9]=i+1;// 0 is for "empty"
			}
		}

//		output2<< " ncluesr "<<ncluesr<<" " ;
//		for(int i=0;i<ncluesr;i++)
//			output2 << cellsFixedData[tcluesr[i]].pt<<" ";
//	    output2<<endl;  

		if((ncluesr-18) ||tcluesr[0] || (tcluesr[1]-3) ||  (tcluesr[2]<9)) return; //safety
		PUZC puzinr=puzin;
		// forces any free bloc 
		for(int imini=0;imini<27;imini++){
			if(tminirow[imini]) continue;
			int dcell=3*imini,fcell=dcell+3,iband=imini/9;;
			// can be any free column or occupied column against that minirow
			for(int ic=dcell;ic<fcell;ic++){

//				output2 << "try add "<< cellsFixedData[ic].pt<<endl;

				int icol=ic%9,icol_cell=tbloc_col[iband][icol];
				for(int iclue=0;iclue<ncluesr;iclue++){
					int cell=tcluesr[iclue];
					if(icol_cell && (cell-(icol_cell-1))) continue;
	// this is a valid permutation,  take all clues less cell
	// change 0 to 3 clues  keep 17-n unchanged  add cell ic
//	output2 << "against "<< cellsFixedData[cell].pt<<endl; 
					puzin=puzinr;
					puzin.puz[cell]='.';
					puzin.puz[ic]='1';
			// pattern process
			//output1 << puzin.puz<<endl;
			//if(1) continue;
					nclues=0;
					for(int i=0;i<ncluesr;i++) 
						if(tcluesr[i]-cell) tclues[nclues++]=tcluesr[i];
					for(int i=0;i<ncluesr-1;i++) tclues_s[i]=tclues[i];
					tclues_s[nclues]=ic;
					Do_99_18_11(17,0,1,puzin.puz);
					// 1 to 4 is very slow trying 1 to 3
					for(int nch=1;nch<4;nch++){	// change 1 to 4 add 1
						COMBINE combi ; 
						combi.First(nclues,nch,tclues,tclues_s);
						while(1 ) {
							tclues_s[17]=ic;
							Do_99_18_11(17-nch,nch,1,puzin.puz);
							if(!combi.Next()) break; 
						}
					}
				}
			}
		}
	}
}

void GO_PAT::Do_99_18_11(int nfix,	int pchange,int qfree,char * puz){
//	output2 << " try nfix "<<nfix<<" pchange " << pchange << "qfree " << qfree 
//		<<" "<<cellsFixedData[tclues_s[nfix+pchange]].pt<<endl;  
//	if(1) return;
	dep.Init(this);
	for(int i=0;i<nfix+pchange;i++){//take all given from the perm
		int ii=tclues_s[i]; 
		int j=puz[ii]-'1';
//		if(ntest<10) output2 << "i=" << i<< "tclues_s[i]=" << ii << " j=" << j << endl; 
		if(i<nfix) dep.Fixer(ii,j); 
		else dep.td[ii].Clear(j);
	} 
	dep.Exo_Game(&tclues_s[nfix],pchange+qfree,0);
}
